/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

#include "BurnDlgJLink.h"
#include <QFileDialog>
#include <QMessageBox>
#include "DataConvertor.h"
#include "BurnCtrl/BurnCtrlFaction.h"

namespace BurnDlg {

namespace  {
    const int MAX_BLOCK_COUNT_1000 = 1000;
    const int COLUMN_WIDTH_SIZE_20 = 20;
    const int COLUMN_WIDTH_SIZE_100 = 100;
    const int COLUMN_WIDTH_SIZE_200 = 200;
    const int COLUMN_MINIMUM_HEIGHT_SIZE_192 = 192;
}
BurnDlgJLink::BurnDlgJLink(ChipType chipType, QWidget *pParent)
    : BurnDlg(pParent),
      ui(new Ui::BurnDlgJLink),
      actSettings(new QAction(stringClass.GetActionJLinkSettings())),
      actImportConfig(new QAction(stringClass.GetActionImportConfig())),
      actSaveConfig(new QAction(stringClass.GetActionSaveConfig())),
      actChangeChip(new QAction(stringClass.GetChangeChip())),
      actAbout(new QAction(stringClass.GetAbout())),
      jLinksetting(new DiaglogJLinkSetting())
{
    burnInfo.clear();
    binModel = new BinFileModel();
    BurnDlg::chipType = chipType;
    this->BurnDlgJLink::InitBurnCtrl();
    if (ui == nullptr || actSettings == nullptr || actChangeChip == nullptr || actAbout == nullptr) {
        return;
    }
    ui->setupUi(this);
    ui->menuSetting->addAction(actSettings);
    ui->menuSetting->addMenu(menuWifiLanguage);
    ui->menuOption->addAction(actChangeChip);
    ui->menuHelp->addAction(actAbout);
    ui->progressBarReceive->setRange(0, SHRT_MAX);
    ui->progressBarReceive->setValue(0);
    ui->textEditReceive->setReadOnly(true);
    ui->textEditReceive->document()->setMaximumBlockCount(MAX_BLOCK_COUNT_1000);
    ui->textEditReceive->setTextInteractionFlags(Qt::NoTextInteraction);
    InitConnect();
    InitTableView();
    InitMenus();
    if (burnCtrl == nullptr) {
        return;
    }
    burnCtrl->StartWiteMonitoring();
}

BurnDlgJLink::~BurnDlgJLink()
{
    if (ui != nullptr) {
        delete ui;
        ui = nullptr;
    }

    if (actSettings != nullptr) {
        delete actSettings;
        actSettings = nullptr;
    }

    if (actImportConfig != nullptr) {
        delete actImportConfig;
        actImportConfig = nullptr;
    }

    if (actSaveConfig != nullptr) {
        delete actSaveConfig;
        actSaveConfig = nullptr;
    }

    if (actChangeChip != nullptr) {
        delete actChangeChip;
        actChangeChip = nullptr;
    }

    if (actAbout != nullptr) {
        delete actAbout;
        actAbout = nullptr;
    }

    if (binModel != nullptr) {
        delete binModel;
        binModel = nullptr;
    }

    if (jLinksetting != nullptr) {
        delete jLinksetting;
        jLinksetting = nullptr;
    }
    if (encryptBuffer.bufferData != nullptr) {
        delete [] encryptBuffer.bufferData;
        encryptBuffer.bufferData = nullptr;
    }
    encryptBuffer.bufferLen = 0;
}

void BurnDlgJLink::InitConnect()
{
    // setting
    if (actSettings != nullptr) {
        connect(actSettings, &QAction::triggered, this, &BurnDlgJLink::SlotShowMenuSettings);
    }
    if (actChangeChip != nullptr) {
        connect(actChangeChip, &QAction::triggered, this, &BurnDlgJLink::SlotShowChangeChip);
    }
    // help
    if (actAbout != nullptr) {
        connect(actAbout, &QAction::triggered, this, &BurnDlgJLink::SlotShowAbout);
    }
    // button
    if (ui == nullptr) {
        return;
    }
    connect(ui->btnSelectFile, &QPushButton::clicked, this, &BurnDlgJLink::SlotBnClickedButtonSelectfile);
    connect(ui->btnStartBurn, &QPushButton::clicked, this,  &BurnDlgJLink::SlotBnClickedButtonStartburn);
    // tableView
    connect(ui->tableView->horizontalHeader(), &QHeaderView::sectionClicked, this,
            &BurnDlgJLink::SlotBnClickedTableHeader);
    connect(ui->tableView, &QTableView::clicked, this, &BurnDlgJLink::SlotBnClickedTableView);
    connect(ui->tableView, &QTableView::doubleClicked, this, &BurnDlgJLink::SlotBnDoubleClickedTableView);
    // burnctrl
    if (burnCtrl == nullptr) {
        return;
    }
    connect(burnCtrl, &BurnCtrl::SignalBurnFileFinish, this, &BurnDlgJLink::SlotBurnFileFinish);
    connect(burnCtrl, &BurnCtrl::SignalInsertPlainText, this, &BurnDlgJLink::SlotInsertPlainText);
    connect(burnCtrl, &BurnCtrl::SignalBurnFileFailed, this, &BurnDlgJLink::SlotBurnFileFailed);
    connect(burnCtrl, &BurnCtrl::SignalSetProgressValue, this, &BurnDlgJLink::SlotSetProgress);
}

void BurnDlgJLink::SlotShowMenuSettings()
{
    if (jLinksetting != nullptr) {
        jLinksetting->show();
    }
}

void BurnDlgJLink::SlotBnClickedButtonSelectfile()
{
    QString filePath = QFileDialog::getOpenFileName(this, tr("Select File"), "", stringClass.GetIdsString32941());
    if (!filePath.isEmpty()) {
        AnalyseBinFile(filePath);
    }
}

void BurnDlgJLink::AnalyseBinFile(QString filePath)
{
    if (burnCtrl == nullptr || burnCtrl->IsBusy()) {
        QMessageBox::critical(this, stringClass.GetMessageError(),
                              stringClass.GetIdsString32984(), stringClass.GetYes());
        return;
    }
    if (ui == nullptr || binModel == nullptr) {
        return;
    }
    ui->lineEditSeleteFile->setText(filePath);
    binModel->ClearData();
    QString version;
    BIN_INFO_ARRAY infoArray;
    QMap<int, BIN_INFO> mapBinInfo = binModel->GetMapBinFileInfo();
    DataConvertor::AnalysMultifBin(ui->lineEditSeleteFile->text(), infoArray, version,
                                   isEncrypt, encryptBuffer);
    for (int i = 0; i < infoArray.GetSize(); i++) {
        if (infoArray.GetAt(i).type == IMAGE_TYPE::IMAGE_TYPE_SMALL_SSB ||
            infoArray.GetAt(i).type == IMAGE_TYPE::IMAGE_TYPE_SMALL_SSB_SHA) {
            continue;
        } else {
            mapBinInfo[mapBinInfo.size()] = infoArray.GetAt(i);
        }
    }
    QMap<int, bool> mapCheck;
    for (int i = 0; i < mapBinInfo.size(); i++) {
        mapCheck[i] = true;
    }
    binModel->FetchData(mapCheck);
    binModel->FetchData(mapBinInfo);
    UpdateVersion(version);
}

void BurnDlgJLink::UpdateVersion(const QString &version) const
{
    if (ui == nullptr) {
        return;
    }
    if (!version.isEmpty()) {
        QString strVersion = tr("Version ") + version;
        ui->verson->setText(strVersion);
    } else {
        ui->verson->setText(version);
    }
}

void BurnDlgJLink::InitTableView() const
{
    if (ui == nullptr || binModel == nullptr) {
        return;
    }
    ui->tableView->setModel(binModel);
    ui->tableView->setDragEnabled(true);
    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    ui->tableView->setDefaultDropAction(Qt::MoveAction);
    ui->tableView->setDragDropMode(QAbstractItemView::InternalMove);
    ui->tableView->setColumnWidth(TABLEVIEW_COLUMN_CHECK, COLUMN_WIDTH_SIZE_20);
    ui->tableView->setColumnWidth(TABLEVIEW_COLUMN_ADD, COLUMN_WIDTH_SIZE_20);
    ui->tableView->setColumnWidth(TABLEVIEW_COLUMN_DELETE, COLUMN_WIDTH_SIZE_20);
    ui->tableView->setColumnWidth(TABLEVIEW_COLUMN_NAME, COLUMN_WIDTH_SIZE_100);
    ui->tableView->setColumnWidth(TABLEVIEW_COLUMN_PAHT, COLUMN_WIDTH_SIZE_200);
    ui->tableView->setMinimumHeight(COLUMN_MINIMUM_HEIGHT_SIZE_192);
    ui->tableView->horizontalHeader()->setSectionResizeMode(TABLEVIEW_COLUMN_CHECK, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setSectionResizeMode(TABLEVIEW_COLUMN_ADD, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setSectionResizeMode(TABLEVIEW_COLUMN_DELETE, QHeaderView::Fixed);
}

void BurnDlgJLink::InitMenus()
{
    this->tableViewMenu = new QMenu(this);
    QAction *createNewFileAction = new QAction(stringClass.GetCreateNewFile());
    if (createNewFileAction != nullptr) {
        this->tableViewMenu->addAction(createNewFileAction);
        connect(createNewFileAction, &QAction::triggered, this, &BurnDlgJLink::SlotCreateNewFwpkgFile);
    }
    QAction *saveSpiltFileAction = new QAction(stringClass.GetSaveSplitFile());
    if (saveSpiltFileAction != nullptr) {
        this->tableViewMenu->addAction(saveSpiltFileAction);
        connect(saveSpiltFileAction, &QAction::triggered, this, &BurnDlgJLink::SlotSaveSpiltFwpkgFile);
    }
}

void BurnDlgJLink::contextMenuEvent(QContextMenuEvent *event)
{
    Q_UNUSED(event);
    if (!ui->tableView->selectionModel()->currentIndex().isValid()) {
        return;
    }
    this->tableViewMenu->exec(QCursor::pos());
}

void BurnDlgJLink::SlotCreateNewFwpkgFile()
{
    CreateNewFwpkgFile(ui->lineEditSeleteFile->text());
}

void BurnDlgJLink::SlotSaveSpiltFwpkgFile()
{
    SaveSpiltFwpkgFile(ui->lineEditSeleteFile->text());
}

void BurnDlgJLink::SlotBnClickedButtonStartburn()
{
    if (burnCtrl == nullptr || ui == nullptr || binModel == nullptr) {
        return;
    }

    if (ui->btnStartBurn->text() == stringClass.GetStartBurn()) {
        UpdateList();
        burnInfo.clear();
        ui->progressBarReceive->setValue(0);
        burnCtrl->SetIsCancel(FALSE);
        QMap<int, BIN_INFO> binInfo = binModel->GetMapBinFileInfo();
        QMap<int, BIN_INFO> checkBinInfo;
        QMap<int, bool> binCheck = binModel->GetMapCheck();
        int i = 0;
        for (auto it = binInfo.begin(); it != binInfo.end(); it++) {
            if (!QFile(it->path).exists()) {
                QMessageBox::warning(nullptr, MESSAGE_BURN_TOOL, it->path + tr(" file path does not exist."));
                ui->btnStartBurn->setText(stringClass.GetStartBurn());
                return;
            }
            if (binCheck[it.key()]) {
                checkBinInfo[i++] = it.value();
            }
        }
        if (checkBinInfo.size() == 0) {
            QMessageBox::warning(nullptr, MESSAGE_BURN_TOOL, stringClass.GetNoValidFlashFile());
            ui->btnStartBurn->setText(stringClass.GetStartBurn());
            return;
        }
        ui->textEditReceive->clear();
        burnCtrl->InitBurnCmdByArray(checkBinInfo);
        ui->btnStartBurn->setText(stringClass.GetStopBurn());
        emit SignalSendMsgInBurnDlg(static_cast<long>(WiteThreadMsg::WITE_THREAD_MSG_STARTCONNECT), 0, 0);
    } else {
        emit SignalSendMsgInBurnDlg(static_cast<long>(WiteThreadMsg::WITE_THREAD_MSG_CLOSE_JLINK), 0, 0);
        ui->btnStartBurn->setText(stringClass.GetStartBurn());
    }
}

void BurnDlgJLink::UpdateList()
{
    if (binModel == nullptr) {
        return;
    }
    int nRow = binModel->rowCount();
    if (nRow > 0x1000) {
        return;
    }
    std::vector<QString> pathArray;
    for (int i = 0; i < nRow; i++) {
        if (binModel->GetCheck(i)) {
            QString path = binModel->GetValue(i, TABLEVIEW_COLUMN_PAHT);
            pathArray.push_back(path);
        }
    }
    std::vector<QString> result;
    for (auto item : pathArray) {
        bool needAddDlgJLink = true;
        for (auto itemElement : result) {
            if (itemElement == item) {
                needAddDlgJLink = false;
                break;
            }
        }
        if (needAddDlgJLink) {
            result.push_back(item);
        }
    }
    QString version;
    for (auto item1 : result) {
        BIN_INFO_ARRAY infoArray;
        DataConvertor::AnalysMultifBin(item1, infoArray, version, isEncrypt, encryptBuffer);
        UpdateList(infoArray);
    }
}

void BurnDlgJLink::UpdateList(BIN_INFO_ARRAY &info) const
{
    if (binModel == nullptr) {
        return;
    }
    for (int i = 0; i < info.GetSize(); i++) {
        BIN_INFO item = info.GetAt(i);
        int colNum = binModel->rowCount(); // 取行数
        if (colNum > 0x1000) {
            break;
        }
        QMap<int, BIN_INFO> mpBinInfo = binModel->GetMapBinFileInfo();
        for (int j = 0; j < colNum; j++) {
            if ((!item.fileName.isEmpty()) && binModel->GetCheck(j) &&
                item.path == mpBinInfo[j].path && item.fileName == mpBinInfo[j].fileName &&
                item.type == mpBinInfo[j].type && (mpBinInfo[j].fileIndex != item.fileIndex ||
                mpBinInfo[j].fileSize != item.fileSize || mpBinInfo[j].burnAddr != item.burnAddr ||
                mpBinInfo[j].burnSize != item.burnSize)) {
                mpBinInfo[j].fileIndex = item.fileIndex;
                mpBinInfo[j].fileSize = item.fileSize;
                mpBinInfo[j].burnAddr = item.burnAddr;
                mpBinInfo[j].burnSize = item.burnSize;
            } else if (item.fileName.isEmpty() && binModel->GetCheck(j) && item.path == mpBinInfo[j].path &&
                       item.fileName == mpBinInfo[j].fileName && item.fileSize != mpBinInfo[j].fileSize) {
                mpBinInfo[j].fileSize = item.fileSize;
            }
        }
        binModel->FetchData(mpBinInfo);
    }
}

void BurnDlgJLink::InitBurnCtrl()
{
    BurnCtrlFaction faction;
    burnCtrl = faction.GetBurnCtrl(chipType);
    if (burnCtrl != nullptr) {
        burnCtrl->SetBurnDlg(this);
    }
}

void BurnDlgJLink::SlotBurnFileFinish()
{
    if (ui == nullptr) {
        return;
    }
    RemoveTempDir();
    ui->btnStartBurn->setText(stringClass.GetStartBurn());
    ui->progressBarReceive->setValue(SHRT_MAX);
    SlotInsertPlainText(IDS_STRING_32879 + "\n");
    SlotInsertPlainText(stringClass.GetIdsString32880() + "\n");
    SlotInsertPlainText(IDS_STRING_32879 + "\n");
}

void BurnDlgJLink::RemoveTempDir() const
{
    QString saveDir = QCoreApplication::applicationDirPath() + "/tempFileJlink";
    QDir dir(saveDir);
    if (dir.exists()) {
        dir.removeRecursively();
    }
}

void BurnDlgJLink::SlotSetProgress(double pos) const
{
    if (ui == nullptr) {
        return;
    }
    qDebug() << __FUNCTION__ << pos;
    ui->progressBarReceive->setValue(pos);
}

void BurnDlgJLink::SlotInsertPlainText(const QString &editStr)
{
    if (ui == nullptr) {
        return;
    }
    ui->textEditReceive->insertPlainText(editStr);
    ui->textEditReceive->ensureCursorVisible();
    ui->textEditReceive->setFocus();
}

void BurnDlgJLink::SlotBurnFileFailed()
{
    if (ui == nullptr) {
        return;
    }
    ui->btnStartBurn->setText(stringClass.GetStartBurn());
    SlotInsertPlainText(IDS_STRING_32879 + "\n");
    SlotInsertPlainText(stringClass.GetIdsString32881());
    SlotInsertPlainText(IDS_STRING_32879 + "\n");
    ui->progressBarReceive->setValue(0);
}

}
